/**
 * Copyright (c) 2013-Now http://jeesite.com All rights reserved.
 * 丁剑修改首次访问绑定组织机构代码
 */
package com.jeesite.modules.sys.web;

import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.fasterxml.jackson.annotation.JsonView;
import com.jeesite.common.codec.DesUtils;
import com.jeesite.common.config.Global;
import com.jeesite.common.lang.StringUtils;
import com.jeesite.common.shiro.filter.FormAuthenticationFilter;
import com.jeesite.common.shiro.realm.BaseAuthorizingRealm;
import com.jeesite.common.shiro.realm.LoginInfo;
import com.jeesite.common.web.BaseController;
import com.jeesite.common.web.CookieUtils;
import com.jeesite.common.web.http.ServletUtils;
import com.jeesite.modules.sys.entity.Menu;
import com.jeesite.modules.sys.entity.User;
import com.jeesite.modules.sys.entity.Company;
import com.jeesite.modules.sys.utils.PwdUtils;
import com.jeesite.modules.sys.utils.UserUtils;
import com.jeesite.modules.sys.service.CompanyService;

/**
 * 登录Controller
 * @author ThinkGem
 * @version 2017-03-25
 */
@Controller
@RequestMapping(value = "${adminPath}")
public class LoginController extends BaseController{

    @Autowired
    private CompanyService companyService;
    /**
     * 管理登录
     */
    @RequestMapping(value = "login", method = RequestMethod.GET)
    public String login(HttpServletRequest request, HttpServletResponse response, Model model) {
        // 地址中如果包含JSESSIONID，则跳转一次，去掉JSESSIONID信息。
        // 验证单机版是否绑定企业身份信息start

//        List<Company> list =companyService.findList(new Company());
//        if(list.size()<=0){
//            return "modules/InCompanyPage/sysLogin";
//        }

        // 验证单机版是否绑定企业身份信息end
        if (StringUtils.containsIgnoreCase(request.getRequestURI(), ";JSESSIONID=")){
            String queryString = request.getQueryString();
            queryString = queryString == null ? "" : "?" + queryString;
            ServletUtils.redirectUrl(request, response, adminPath + "/login" + queryString);
            return null;
        }

        LoginInfo loginInfo = UserUtils.getLoginInfo();

        // 如果已经登录，则跳转到管理首页
        if(loginInfo != null){
            String queryString = request.getQueryString();
            queryString = queryString == null ? "" : "?" + queryString;
            ServletUtils.redirectUrl(request, response, adminPath + "/index" + queryString);
            return null;
        }

        // 如果是登录操作，跳转到此，则认为是登录失败（支持GET登录时传递__login=true参数）
        if (WebUtils.isTrue(request, "__login")){
            return loginFailure(request, response, model);
        }

        // 如果已登录，再次访问主页，则退出原账号。
        if (!Global.TRUE.equals(Global.getConfig("shiro.isAllowRefreshIndex"))){
            CookieUtils.setCookie(response, "LOGINED", "false");
        }

        // 是否显示验证码
        model.addAttribute("isValidCodeLogin", Global.getConfigToInteger("sys.login.failedNumAfterValidCode", "200") == 0);

        //获取当前会话对象
        Session session = UserUtils.getSession();
        model.addAttribute("sessionid", (String)session.getId());

        // 获取登录参数
        Map<String, Object> paramMap = ServletUtils.getExtParams(request);

        // 如果登录设置了语言，则切换语言
        if (paramMap.get("lang") != null){
            Global.setLang((String)paramMap.get("lang"), request, response);
        }

        // 如果是Ajax请求，返回Json字符串。
        if (ServletUtils.isAjaxRequest((HttpServletRequest)request)){
            model.addAttribute("result", "login");
            model.addAttribute("message", text("sys.login.notLongIn"));
            return ServletUtils.renderObject(response, model);
        }

        // 返回指定用户类型的登录页视图
        String userType = (String)paramMap.get("userType");
        if (StringUtils.isNotBlank(userType)){
            String view = UserUtils.getUserTypeValue(userType, "loginView");
            if(StringUtils.isNotBlank(view)){
                return view;
            }
        }

        return "modules/sys/sysLogin";
    }

    /**
     * 登录失败，真正登录的POST请求由Filter完成
     */
    @RequestMapping(value = "login", method = RequestMethod.POST)
    public String loginFailure(HttpServletRequest request, HttpServletResponse response, Model model) {
        LoginInfo loginInfo = UserUtils.getLoginInfo();

        // 如果已经登录，则跳转到管理首页
        if(loginInfo != null){
            String queryString = request.getQueryString();
            queryString = queryString == null ? "" : "?" + queryString;
            ServletUtils.redirectUrl(request, response, adminPath + "/index" + queryString);
            return null;
        }

        String username = WebUtils.getCleanParam(request, FormAuthenticationFilter.DEFAULT_USERNAME_PARAM);
        boolean rememberMe = WebUtils.isTrue(request, FormAuthenticationFilter.DEFAULT_REMEMBER_ME_PARAM);
        boolean rememberUserCode = WebUtils.isTrue(request, FormAuthenticationFilter.DEFAULT_REMEMBER_USERCODE_PARAM);
        String params = WebUtils.getCleanParam(request, FormAuthenticationFilter.DEFAULT_PARAMS_PARAM);
        String exception = (String)request.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);
        String message = (String)request.getAttribute(FormAuthenticationFilter.DEFAULT_MESSAGE_PARAM);

        String secretKey = Global.getProperty("shiro.loginSubmit.secretKey");
        if (StringUtils.isNotBlank(secretKey)){
            username = DesUtils.decode(username, secretKey);
        }

        model.addAttribute(FormAuthenticationFilter.DEFAULT_USERNAME_PARAM, username);
        model.addAttribute(FormAuthenticationFilter.DEFAULT_REMEMBER_ME_PARAM, rememberMe);
        model.addAttribute(FormAuthenticationFilter.DEFAULT_REMEMBER_USERCODE_PARAM, rememberUserCode);
        model.addAttribute(FormAuthenticationFilter.DEFAULT_PARAMS_PARAM, params);
        Map<String, Object> paramMap = ServletUtils.getExtParams(request);
        for (Entry<String, Object> entry : paramMap.entrySet()){
            model.addAttribute(FormAuthenticationFilter.DEFAULT_PARAM_PREFIX_PARAM + entry.getKey(), entry.getValue());
        }
        model.addAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME, exception);

        // 如果登录设置了语言，则切换语言
        if (paramMap.get("lang") != null){
            Global.setLang((String)paramMap.get("lang"), request, response);
        }

        model.addAttribute(FormAuthenticationFilter.DEFAULT_MESSAGE_PARAM, text(message));

        // 非授权异常，登录失败，验证码加1。
        if (!UnauthorizedException.class.getName().equals(exception)){
            model.addAttribute("isValidCodeLogin", BaseAuthorizingRealm.isValidCodeLogin(username,
                    (String)paramMap.get("corpCode"), (String)paramMap.get("deviceType"), "failed"));
        }

        //获取当前会话对象
        Session session = UserUtils.getSession();
        model.addAttribute("sessionid", (String)session.getId());

        // 登录操作如果是Ajax操作，直接返回登录信息字符串。
        if (ServletUtils.isAjaxRequest(request)){
            model.addAttribute("result", Global.FALSE);
            return ServletUtils.renderObject(response, model);
        }

        // 返回指定用户类型的登录页视图
        String userType = (String)paramMap.get("userType");
        if (StringUtils.isNotBlank(userType)){
            String view = UserUtils.getUserTypeValue(userType, "loginView");
            if(StringUtils.isNotBlank(view)){
                return view;
            }
        }

        return "modules/sys/sysLogin";
    }

    /**
     * 登录成功，进入管理首页
     */
    @RequestMapping(value = "index")
    public String index(HttpServletRequest request, HttpServletResponse response, Model model) {
        // 地址中如果包含JSESSIONID，则跳转一次，去掉JSESSIONID信息。
        if (StringUtils.containsIgnoreCase(request.getRequestURI(), ";JSESSIONID=")){
            String queryString = request.getQueryString();
            queryString = queryString == null ? "" : "?" + queryString;
            ServletUtils.redirectUrl(request, response, adminPath + "/index" + queryString);
            return null;
        }

        // 验证下用户权限，以便调用doGetAuthorizationInfo方法，保存单点登录登出句柄
        Subject subject = SecurityUtils.getSubject();
        if (subject == null || !subject.isPermitted("user")){
            if (subject != null){
                subject.logout();
            }
            String queryString = request.getQueryString();
            queryString = queryString == null ? "" : "?" + queryString;
            ServletUtils.redirectUrl(request, response, adminPath + "/login" + queryString);
            return null;
        }

        //获取登录用户信息
        LoginInfo loginInfo = UserUtils.getLoginInfo();

        // 未加载shiro模块时会为空，直接访问则提示操作权限不足。
        if(loginInfo == null){
            UserUtils.getSubject().logout();
            String queryString = request.getQueryString();
            queryString = queryString == null ? "" : "?" + queryString;
            ServletUtils.redirectUrl(request, response, adminPath + "/login" + queryString);
            return null;
        }

        // 当前用户对象信息
        User user = UserUtils.get(loginInfo.getId());
        if (user == null){
            UserUtils.getSubject().logout();
            String queryString = request.getQueryString();
            queryString = queryString == null ? "" : "?" + queryString;
            ServletUtils.redirectUrl(request, response, adminPath + "/login" + queryString);
            return null;
        }
        model.addAttribute("user", user); // 设置当前用户信息

        //获取当前会话对象
        Session session = UserUtils.getSession();

        // 是否是登录操作
        boolean isLogin = "true".equals(session.getAttribute("__login"));
        if (isLogin){
            // 获取后接着清除，防止下次获取仍然认为是登录状态
            session.removeAttribute("__login");
            // 设置共享SessionId的Cookie值（第三方系统使用）
            String cookieName = Global.getProperty("session.shareSessionIdCookieName");
            if (StringUtils.isNotBlank(cookieName)){
                CookieUtils.setCookie((HttpServletResponse)response, cookieName, (String)session.getId());
            }
            // 如果登录设置了语言，则切换语言
            if (loginInfo.getParam("lang") != null){
                Global.setLang(loginInfo.getParam("lang"), request, response);
            }
        }

        // 获取登录成功后跳转的页面
        String successUrl = request.getParameter("__url");
        if (StringUtils.isBlank(successUrl)){
            successUrl = Global.getProperty("shiro.successUrl");
        }

        // 登录操作如果是Ajax操作，直接返回登录信息字符串。
        if (ServletUtils.isAjaxRequest(request)){
            model.addAttribute("result", Global.TRUE);
            // 如果是登录，则返回登录成功信息，否则返回获取成功信息
            if (isLogin){
                model.addAttribute("message", text("sys.login.success"));
            }else{
                model.addAttribute("message", text("sys.login.getInfo"));
            }
            model.addAttribute("sessionid", (String)session.getId());
            if (!StringUtils.contains(successUrl, "://")){
                successUrl = request.getContextPath() + successUrl;
            }
            model.addAttribute("__url", successUrl); // 告诉浏览器登录后跳转的页面
            return ServletUtils.renderObject(response, model);
        }
        // 如果是登录操作，则跳转到登录成功页
        else if (isLogin){
            return REDIRECT + successUrl;
        }

        // 是否允许刷新主页，如果已登录，再次访问主页，则退出原账号。
        if (!Global.getConfigToBoolean("shiro.isAllowRefreshIndex", "true")){
            String logined = CookieUtils.getCookie(request, "LOGINED");
            if (StringUtils.isBlank(logined) || "false".equals(logined)){
                CookieUtils.setCookie(response, "LOGINED", "true");
            }else if (StringUtils.equals(logined, "true")){
                UserUtils.getSubject().logout();
                CookieUtils.setCookie(response, "LOGINED", "false");
                String queryString = request.getQueryString();
                queryString = queryString == null ? "" : "?" + queryString;
                return REDIRECT + adminPath + "/login" + queryString;
            }
        }

        // 初始密码策略和密码修改策略验证（0：关闭；1：提醒用户；2：强制修改初始或旧密码）
        String passwordModifyUrl = PwdUtils.passwordModifyValid(user, model);
        if (passwordModifyUrl != null){
            try {
                request.getRequestDispatcher(passwordModifyUrl).forward(request, response);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }

        // 非无类型用户，自动根据用户类型设置默认菜单的归属系统（个性化示例）
        //if (!User.USER_TYPE_NONE.equals(user.getUserType())){
        //	session.setAttribute("sysCode", user.getUserType());
        //	UserUtils.removeCache(UserUtils.CACHE_AUTH_INFO+"_"+session.getId());
        //}

        // 返回指定用户类型的首页视图
        String view = UserUtils.getUserTypeValue(user.getUserType(), "indexView");
        if(StringUtils.isNotBlank(view)){
            return view;
        }

        // 返回主页面视图
        return "modules/sys/sysIndex";
    }

    /**
     * 获取侧边栏菜单数据
     */
    @RequiresPermissions("user")
    @RequestMapping(value = "index/menuTree")
    public String indexMenuTree(String parentCode) {
        return "modules/sys/sysIndex/menuTree";
    }

    /**
     * 获取当前用户权限字符串数据（移动端用）
     */
    @RequiresPermissions("user")
    @RequestMapping(value = "authInfo")
    @ResponseBody
    public AuthorizationInfo authInfo() {
        return UserUtils.getAuthInfo();
    }

    /**
     * 获取当前用户菜单数据（移动端用）
     */
    @RequiresPermissions("user")
    @RequestMapping(value = "menuTree")
    @ResponseBody
    @JsonView(Menu.SimpleView.class)
    public List<Menu> menuTree(String parentCode) {
        return UserUtils.getMenuTreeByParentCode(parentCode);
    }

    /**
     * 切换系统菜单（仅超级管理员有权限）
     */
    @RequiresPermissions("user")
    @RequestMapping(value = "switch/{sysCode}")
    public String switchSys(@PathVariable String sysCode) {
        Session session = UserUtils.getSession();
        if (StringUtils.isNotBlank(sysCode)){
            session.setAttribute("sysCode", sysCode);
        }else{
            session.removeAttribute("sysCode");
        }
        UserUtils.removeCache(UserUtils.CACHE_AUTH_INFO+"_"+session.getId());
        return REDIRECT + adminPath + "/index";
    }

    /**
     * 切换角色菜单（仅超级管理员有权限）
     */
    @RequiresPermissions("user")
    @RequestMapping(value = {"switchRole","switchRole/{roleCode}"})
    public String switchRole(@PathVariable(required=false) String roleCode) {
        Session session = UserUtils.getSession();
        if (StringUtils.isNotBlank(roleCode)){
            session.setAttribute("roleCode", roleCode);
        }else{
            session.removeAttribute("roleCode");
        }
        UserUtils.removeCache(UserUtils.CACHE_AUTH_INFO+"_"+session.getId());
        return REDIRECT + adminPath + "/index";
    }

    /**
     * 切换主题
     */
    @RequiresPermissions("user")
    @RequestMapping(value = "switchSkin/{skinName}")
    public String switchSkin(@PathVariable String skinName, HttpServletRequest request, HttpServletResponse response) {
        LoginInfo loginInfo = UserUtils.getLoginInfo();
        if (StringUtils.isNotBlank(skinName) && !"select".equals(skinName)){
            CookieUtils.setCookie(response, "skinName_" + loginInfo.getId(), skinName);
            return REDIRECT + adminPath + "/index";
        }
        return "modules/sys/sysSwitchSkin";
    }

    /**
     * 个人桌面页面
     */
    @RequiresPermissions("user")
    @RequestMapping(value = "desktop")
    public String desktop(HttpServletRequest request, HttpServletResponse response, Model model) {
        return "modules/sys/sysDesktop";
    }

}
